// litgroups.cpp
// Customizer_Base
// Protea Customizer/Customizer Pro / Business Logic for managing literal groups
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Please send correspondence to:
//
// theproteaproject@gmail.com
//

#include "base_setup.h"

//////////////////////////////////////////////////////////////////////////////
//
// LIT_GROUP Subtransactions
//
//////////////////////////////////////////////////////////////////////////////

//@ SEC 3
//@ CHA Lit Group Verify
//@ COD LitGroupVerify
//@ TAB LIT_GROUP Read
//@ GEN Use LitGroupVerify to verify a literal group record
void LitGroupVerify( XCBuffer* buf, XCTransactionVars* vars, verify_type verify_mode, bool pro_mode ) 
{
	TRANS_INFUNC( LitGroupVerify );

	XCField* lit_nbr = vars->buffer->GetField( FLD_LIT_GROUP_NBR );

	//@ If verifying an ADD or CHANGE transaction
	if (verify_mode == VERIFY_ADD || verify_mode == VERIFY_CHANGE) {
		//@ GRS

		//@ SUB ValidateName to check for a valid name
		ValidateName( FLD_LIT_GROUP_NAME, vars->buffer, ERR_LIT_GROUP, vars );

		//@ GRE
	} else {
		//@ GRS
		//@ Otherwise,
		//@ Ensure that the either LIT_GROUP_NAME or LIT_GROUP_NBR field is entered
		XCField* temp = vars->buffer->GetField( FLD_LIT_GROUP_NAME );
		if ( temp->IsBlank() && (!lit_nbr || lit_nbr->IsBlank()))
			vars->Errors->Add( ERR_IS_BLANK, SEV_CRITICAL, FLD_LIT_GROUP_NAME, 1, temp );
		//@ GRE
	};

	//@ If verifying an ADD transaction,
	if (verify_mode == VERIFY_ADD) {
		//@ GRS

		//@ UTL LookupNumberFromName to convert literal group name into a literal group number
		//@ ERR C (ALREADY_EXISTS) Literal Group already exists
		if ( LookupNumberFromName( vars, vars->buffer, buf, FLD_LIT_GROUP_NBR, FLD_LIT_GROUP_NAME, FMT_LIT_GROUP ))
			vars->Errors->Add( ERR_ALREADY_EXISTS, SEV_CRITICAL, FLD_LIT_GROUP_NAME, 1, ERR_LIT_GROUP );

		//@ GRE
	} else {
		//@ GRS

		//@ SUB LookupNumberFromName to obtain literal group number
		//@ ERR E (DOESNT_EXIST) Literal Group doesn't exist
		if (!lit_nbr || lit_nbr->IsBlank()) {
			if (!LookupNumberFromName( vars, vars->buffer, buf, FLD_LIT_GROUP_NBR, FLD_LIT_GROUP_NAME, FMT_LIT_GROUP ))
				vars->Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_LIT_GROUP_NAME, 1, ERR_LIT_GROUP );
		};

		//@ SUB LitGroupRetrieve to verify that we have a valid literal group
		//@ ERR E (DOESNT_EXIST) Literal Group doesn't exist
		if (!LitGroupRetrieve( buf, vars ))
			vars->Errors->Add( ERR_DOESNT_EXIST, SEV_CRITICAL, FLD_LIT_GROUP_NAME, 1, ERR_LIT_GROUP );

		//@ Check system/user level settings if not in pro mode
		if (!pro_mode && verify_mode != VERIFY_REVIEW) {
			//@ GRS

			//@ If a system object, error:
			//@ ERR C (CHANGE_CRITICAL_OBJECT)
			if (buf->GetField( FLD_SYSTEM_OBJECT )->GetBool())
				vars->Errors->Add( ERR_CHANGE_CRITICAL_OBJECT, SEV_CRITICAL );

			//@ GRE
		};
		//@ GRE
	};

	TRANS_OUTFUNC();
};



//@ SEC 3
//@ CHA Lit Group Add
//@ COD LitGroupAdd
//@ TAB LIT_GROUP Write
//@ GEN Use LitGroupAdd to add a literal group record
void LitGroupAdd( XCBuffer* buf, XCTransactionVars* vars, bool pro_mode ) 
{
	TRANS_INFUNC( LitGroupAdd );

	XCDBStatement* stmt = NULL;
	XCBuffer* temp = NULL;
	XCSQLGen* query = vars->query;

	long last_number = 0;

	//@ Determine the next available literal group number
	temp = App->CreateBuffer( FMT_LIT_GROUP );
	try {
		XCOrder ord;
		XCCompare comp;
		bool found = false;

		query->MakeSELECT( temp );
		query->AddWHERE( buf->GetField( FLD_APPL_NBR ), &comp );
		query->AddORDERBY( FLD_LIT_GROUP_NBR, &ord );
		stmt = vars->dbtxn->ExecuteSQL( query );
		while ( !found && !stmt->Eof() )
		{
			long value = temp->GetField( FLD_LIT_GROUP_NBR )->GetLong( true );
			if ( value != last_number + 1 )
			{
				// we found a blank space
				found = true;
			}
			else
			{
				last_number = value;
				stmt->MoveNext();
			};
		};

		// Cleanup now
		App->CleanupObjects( 2, &temp, &stmt );

		last_number++;
		buf->GetField( FLD_LIT_GROUP_NBR )->SetLong( last_number );

	} catch( ... ) {
		App->CleanupObjects( 2, &temp, &stmt );
		throw;
	};

	//@ Set the SYSTEM_OBJECT field accordingly
	buf->GetField( FLD_SYSTEM_OBJECT )->SetBool( pro_mode );

	//@ Add the literal group record
	query->MakeFull( SQL_STMT_INSERT, buf );
	vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

	TRANS_OUTFUNC();
};



//@ SEC 3
//@ CHA Lit Group Change
//@ COD LitGroupChange
//@ TAB LIT_GROUP Write
//@ GEN Use to change literal group records
void LitGroupChange( XCBuffer* lit_group, XCBuffer* orig, XCTransactionVars* vars )
{
	TRANS_INFUNC( LitGroupDelete );

	XCSQLGen* query = vars->query;

	//@ Change the literal group record
	query->MakeFull( SQL_STMT_UPDATE, lit_group, orig );
	vars->dbtxn->ExecuteSQL( query );
	
	TRANS_OUTFUNC();
};




//@ SEC 3
//@ CHA Lit Group Delete
//@ COD LitGroupDelete
//@ TAB LIT_GROUP Write
//@ GEN Use to delete literal group records
void LitGroupDelete( XCBuffer* lit_group, XCTransactionVars* vars ) 
{
	TRANS_INFUNC( LitGroupDelete );

	XCSQLGen* query = vars->query;

	//@ Delete the literal group record
	query->MakeFull( SQL_STMT_DELETE, lit_group );
	vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );

	//@ Delete all associated lit_relate records
	XCBuffer* lit_relate = vars->myapp->CreateBuffer( FMT_LIT_RELATE );
	try {
		lit_relate->MoveCorresponding( lit_group, vars->Errors );
		query->MakeDELETE( lit_relate );
		query->AddWHERE( 2, 
			lit_relate->GetField( FLD_APPL_NBR ), 
			lit_relate->GetField( FLD_LIT_GROUP_NBR ));
		vars->dbtxn->ExecuteSQL( query, SQL_NO_RESULT );
	} catch( ... ) {
		lit_relate->Release();
		throw;
	};
	lit_relate->Release();

	TRANS_OUTFUNC();
};




//@ SEC 3
//@ CHA Lit Group Retrieve
//@ COD LitGroupRetrieve
//@ TAB LIT_GROUP Read
//@ GEN Use LitGroupRetrieve to retrieve literal group records

bool LitGroupRetrieve( XCBuffer* buf, XCTransactionVars* vars ) 
{
	TRANS_INFUNC( LitGroupRetrieve );

	bool result;
	XCDBStatement* stmt = NULL;
	XCSQLGen* query = vars->query;

	try {
		query->MakeFull( SQL_STMT_SELECT, buf );
		stmt = vars->dbtxn->ExecuteSQL( query );
		result = (!stmt->Eof());
	} catch( ... ) {
		App->CleanupObjects( 1, &stmt );
		throw;
	};
	App->CleanupObjects( 1, &stmt );

	TRANS_OUTFUNCRET( result );
};




//////////////////////////////////////////////////////////////////////////////
//
// Internal functions
//
//////////////////////////////////////////////////////////////////////////////

void AddLiteralGroupInternal( XCTransactionVars* vars, bool pro_mode ) {
	//@ Create Lit Group buffer
	XCBuffer* lit_group = vars->myapp->CreateBuffer( FMT_LIT_GROUP );
	try {
		//@ Move screen info to transaction buffer
		lit_group->MoveCorresponding( vars->buffer, vars->Errors );
		vars->Errors->Check();

		//@ SUB LitGroupVerify to verify that literal group can be added
		LitGroupVerify( lit_group, vars, VERIFY_ADD, pro_mode );

		//@ Check for errors
		vars->Errors->Check();

		//@ SUB LitGroupAdd to add the new application
		LitGroupAdd( lit_group, vars, pro_mode );

		vars->buffer->MoveCorresponding( lit_group, vars->Errors );
		vars->myapp->TransResponse( vars->result, vars->buffer, TRANS_HEADER_TYPE );
	} catch( ... ) {
		lit_group->Release();
		throw;
	};
	lit_group->Release();
};



void DelLiteralGroupInternal( XCTransactionVars* vars, bool pro_mode ) {
	//@ Create format descriptor buffer
	XCBuffer* TransBuf = vars->myapp->CreateBuffer( FMT_LIT_GROUP, false );
	try {
		//@ Move screen info to transaction buffer
		TransBuf->MoveCorresponding( vars->buffer, vars->Errors );
		vars->Errors->Check();

		//@ SUB LitGroupVerify to verify that record can be deleted
		LitGroupVerify( TransBuf, vars, VERIFY_DELETE, pro_mode );
		vars->Errors->Check();

		TransBuf->DebugDump();

		//@ SUB LitGroupDelete to delete the record.
		LitGroupDelete( TransBuf, vars );
	} catch( ... ) {
		TransBuf->Release();
		throw;
	};
	TransBuf->Release();
};



bool ChgLiteralGroupInternal( XCTransactionVars* vars, bool pro_mode ) {
	XCBuffer* TransBuf = NULL;
	XCBuffer* orig = NULL;
	bool result = false;

	try {
		//@ Create format descriptor buffer
		TransBuf = vars->myapp->CreateBuffer( FMT_LIT_GROUP, false );

		//@ Move screen info to transaction buffer
		TransBuf->MoveCorresponding( vars->buffer, vars->Errors );
		vars->Errors->Check();

		bool ReviewOnly = vars->buffer->IsBlank( 2, FLD_APPL_NBR, FLD_LIT_GROUP_NAME );

		TransBuf->DebugDump();

		//@ SUB LitGroupVerify to verify that record can be deleted
		LitGroupVerify( TransBuf, vars, VERIFY_CHANGE, pro_mode );
		vars->Errors->Check();

		if (!ReviewOnly) {
			orig = TransBuf->Copy();
			TransBuf->MoveCorresponding( vars->buffer, NULL, true );
			TransBuf->MoveField( orig, FLD_LIT_GROUP_NBR );

			//@ SUB LitGroupChange to alter the record.
			LitGroupChange( TransBuf, orig, vars );
			result = true;
		};

		vars->buffer->MoveCorresponding( TransBuf, vars->Errors );
		vars->myapp->TransResponse( vars->result, vars->buffer, TRANS_HEADER_TYPE );
	} catch( ... ) {
		vars->myapp->CleanupObjects( 2, &TransBuf, &orig );
		throw;
	};
	vars->myapp->CleanupObjects( 2, &TransBuf, &orig );
	return result;
};


// Returns the literals contained in the specified literal group
//	TransBuf is a LIT_RELATE buffer
XCDBStatement* GetLitGroup( XCBuffer* TransBuf, XCTransactionVars* vars ) {
	XCField* FieldList[3];
	XCCompare comptemp[2];
	XCField* temp;
	XCSQLGen* query = vars->query;
	int fcount = 0;

	// Formulate select statement
	query->MakeSELECT( TransBuf );

	// If Appl_nbr = 0, select all records
	temp = TransBuf->GetField( FLD_APPL_NBR );
	if (temp->Compare(0) != 0)
		FieldList[ fcount++ ] = temp;

	// If the group number has a value, then select on it
	temp = TransBuf->GetField( FLD_LIT_GROUP_NBR );
	if (temp->Compare(0) != 0)
		FieldList[ fcount++ ] = TransBuf->GetField( FLD_LIT_GROUP_NBR );

	// Terminate the field list
	FieldList[ fcount ] = NULL;

	// Add the where clause to the query
	query->AddWHERE( FieldList, comptemp );

	// Execute the query and return results
	return vars->dbtxn->ExecuteSQL( query );
};
